package io.github.eric.urpc.standalone.server;


import io.github.eric.urpc.core.conn.Connection;
import io.github.eric.urpc.core.conn.ConnectionListener;
import io.github.eric.urpc.core.util.RandomStringGenerator;
import io.github.eric.urpc.server.Server;
import io.github.eric.urpc.server.ServerContext;
import io.github.eric.urpc.standalone.common.CompressionUtil;
import io.github.eric.urpc.standalone.common.msg.PushUsers;
import io.github.eric.urpc.standalone.common.msg.PushUsersFinish;
import io.github.eric.urpc.standalone.common.msg.PushUsersStart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class UserManager implements ConnectionListener {
    private static Logger LOGGER = LoggerFactory.getLogger(UserManager.class);
    private static UserManager Instance;
    public static String USER_ID = "UserId";
    private Map<String, User> userMap = new ConcurrentHashMap<>();
    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

    static {
        Instance = new UserManager();
    }

    public static UserManager getInstance() {
        return Instance;
    }

    public <K, V> List<K> getRandomKeys(Map<K, V> map, int numberOfKeysToPick) {
        if (numberOfKeysToPick >= map.size()) {
            // 如果请求的数量大于或等于map大小，则返回所有键
            return new ArrayList<>(map.keySet());
        }

        Random random = new Random();
        Set<Integer> pickedIndexes = new HashSet<>();

        // 直接生成所需数量的不同随机索引
        while (pickedIndexes.size() < numberOfKeysToPick) {
            pickedIndexes.add(random.nextInt(map.size()));
        }

        List<K> keys = new ArrayList<>(map.keySet());
        return pickedIndexes.stream()
                .map(keys::get)
                .collect(Collectors.toList());
    }

    public UserManager() {
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    LOGGER.info("推送好友列表开始");
                    Collection<Connection> connections = ((ServerContext) Application.SERVER.getServerConfig()).getConnectionManager().getConnections();
                    for (Connection conn : connections) {
                        try {
                            PushUsersStart pushUsersStart = new PushUsersStart();
                            conn.sendAsync(pushUsersStart);
                            PushUsers pushUsers = new PushUsers();
                            pushUsers.setUsers(getRandomKeys(userMap, 100));
                            conn.sendAsync(pushUsers);
                            PushUsersFinish pushUsersFinish = new PushUsersFinish();
                            conn.sendAsync(pushUsersFinish);
                        } catch (Exception e) {
                            LOGGER.warn("[urpc server] server broadcast async message {} to {} error, ignore it and go on",
                                    PushUsers.class.getSimpleName(), conn.getRemoteAddress().getHostString());
                        }
                    }
                    LOGGER.info("推送好友列表结束");
                } catch (Exception e) {
                    LOGGER.error("push all users error", e);
                }
            }
        }, 60, 60, TimeUnit.SECONDS);
    }

    public void addUser(String userId, String userName, String connId) {
        if (userMap.containsKey(userId)) {
            return;
        }
        User user = new User();
        user.setId(userId);
        user.setName(userName);
        user.setConnId(connId);
        Map<String, Object> labels = new HashMap<>();
        labels.put(USER_ID, userId);
        Application.SERVER.setConnectionAttributes(connId, labels);
        userMap.put(userId, user);
        LOGGER.info("用户登录, id {}, name {}, connId {}", userId, userName, connId);
    }

    public void removeUser(String userId, String connId) {
        if (userId == null) {
            return;
        }
        User user = userMap.remove(userId);
        if (user != null) {
            LOGGER.info("用户登出, id {}, name {}, connId {}", user.getId(), user.getName(), connId);
        }
    }

    public User get(String userId) {
        return userMap.get(userId);
    }

    @Override
    public void onConnected(Connection conn) {

    }

    @Override
    public void onDisConnected(Connection conn) {
        String userId = (String) conn.getAttribute(USER_ID);
        LOGGER.info("连接断开, id {}, connId {}", userId, conn.getId());
        removeUser(userId, conn.getId());
    }

    @Override
    public void onAccepted(Connection conn) {

    }

}
